﻿using SQ.Core.Logger;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SQ.Core.Configuration.Log;
using System.IO;
using System.Threading;

namespace SQ.Core.Infrastructure.Logger
{
    public class FileLogger : ILogger
    {
        #region Constantes
        
        private const string FORMATO_MENSAGEM = "{0} {1} MENSAGEM: {2}";
        private const string FORMATO_MENSAGEM_ERRO = "{0} {1} ERRO: {2}";
        private const string EXTENSAO_LOG = ".log";
        private const string NOME_LOG_HISTORICO = "HIST_{0}_{1}";
        private const string FORMATO_DATA_MENSAGEM = "dd/MM/yyyy HH:mm:ss";
        private const string FORMATO_DATA_NOME_LOG_HISTORICO = "yyyyMMddHHmmss";
        private const int TAMANHO_BYTES = 1024;

        #endregion

        #region Atributos

        private StreamWriter arquivo = null;
        private string nomeArquivoCompleto = string.Empty;

        #endregion

        #region Propriedades

        public LogConfiguration Configuracoes
        {
            get;
            set;
        }

        #endregion

        public FileLogger()
        {
            this.Configuracoes = new LogConfiguration();
            this.nomeArquivoCompleto = CriarNomeArquivo(this.Configuracoes.DiretorioArquivo, this.Configuracoes.NomeArquivoLog);

            IniciarArquivo();
        }

        private string CriarNomeArquivo(string diretorio, string nomeArquivo)
        {
            return string.Concat(diretorio, "/", nomeArquivo, EXTENSAO_LOG);
        }

        private void IniciarArquivo()
        {
            arquivo = new StreamWriter(this.nomeArquivoCompleto, false);
        }

        public void LogarMensagem(string mensagem)
        {
            string mensagemFormatada = FormatarMensagem(mensagem);
            Logar(mensagem);
        }

        private string FormatarMensagem(string mensagem)
        {
            return string.Format(FORMATO_MENSAGEM, Thread.CurrentThread.Name, DateTime.Now.ToString(FORMATO_DATA_MENSAGEM), mensagem);
        }

        public void LogarErro(string mensagem)
        {
            string mensagemFormatada = FormatarMensagemErro(mensagem);
            Logar(mensagem);
        }

        private string FormatarMensagemErro(string mensagem)
        {
            return string.Format(FORMATO_MENSAGEM_ERRO, Thread.CurrentThread.Name, DateTime.Now.ToString(FORMATO_DATA_MENSAGEM), mensagem);
        }

        private void Logar(string mensagem)
        {
            lock (this)
            {
                if (ArquivoEstaCheio())
                {
                    ReiniciarArquivo();
                }

                GravarMensagemArquivo(mensagem);
            }
        }

        private bool ArquivoEstaCheio()
        {
            FileInfo informacoesArquivo = new FileInfo(this.nomeArquivoCompleto);

            return informacoesArquivo.Length > (this.Configuracoes.TamanhoArquivo * TAMANHO_BYTES);
        }

        private void ReiniciarArquivo()
        {
            FinalizarArquivo();

            CopiarArquivoParahistorico();

            IniciarArquivo();
        }

        private void FinalizarArquivo()
        {
            arquivo.Close();
        }

        private void CopiarArquivoParahistorico()
        {
            string dataCriacaoHistorico = DateTime.Now.ToString(FORMATO_DATA_NOME_LOG_HISTORICO);

            string nomeArquivoHistorico = string.Format(NOME_LOG_HISTORICO, this.Configuracoes.NomeArquivoLog, dataCriacaoHistorico);

            string destinoLogHistorico = CriarNomeArquivo(this.Configuracoes.DiretorioArquivoHistorico, nomeArquivoHistorico);

            File.Copy(this.nomeArquivoCompleto, destinoLogHistorico);
        }

        private void GravarMensagemArquivo(string mensagem)
        {
            arquivo.WriteLine(mensagem);
            arquivo.Flush();
        }

    }
}
